﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Xml;
using System.Xml.Serialization;
using EggTimer;
using EggTimer.Parsers;

namespace RecipeTracker
{
    //•	Take the recipe program you developed as part of your assignment, and implement the following: 
    //  o	The ability to print a recipe.
    //  o	A built in count down timer with a progress bar.
    //  o	A ComboBox that lists all the available recipes. Selecting from the box will display that recipe.
    //  o	Recipe Categories.  Allow the list of selectable recipes to be filterable by category (Breads, Meats, Desserts, etc).
    //  o	Ingredient filters.  The ability to filter the selectable recipes by up to 5 ingredient filters.  The filters should
    //      work on an ‘Or’ basis.  The user should be able to select one to 5 ingredients and have recipes displayed that contain
    //      at least one of the ingredients.
    //  o	Recipe steps should be presented in a grid, one line per step, with an unbound CheckBox presented at the beginning of
    //      the step.  The CheckBox will be used by the user to mark off what steps have been completed.
    //  o	Ingredient measure should be implemented as a ComboBox, both in grids and stand-alone fields.

    public partial class MainForm : Form
    {
        public List<Recipe> recipes = new List<Recipe>();
        private List<Recipe> filteredOffRecipes = new List<Recipe>();
        private List<Recipe> filteredOffRecipes2 = new List<Recipe>();
        public List<Ingredient> ingredients = new List<Ingredient>();
        private List<ComboBox> comboFilters = new List<ComboBox>();

        private ETimer e;
        
        public MainForm()
        {
            InitializeComponent();
            DataGridViewComboBoxColumn col = (DataGridViewComboBoxColumn)ingredientsDataGridView.Columns[1];
            col.DataSource = Enum.GetValues(typeof(Ingredient.IngredientMeasure));
            LoadRecipes();
            LoadIngredients();
            LoadCategorySelect();
            setUpFiltersComboBoxes();
            recipes.Sort();
            recipeBindingSource.DataSource = recipes;
            recipeBindingSource.CurrentChanged += new EventHandler(recipeBindingSource_CurrentChanged);
            cmbRecipeSelector.DataSource = recipeBindingSource;
            cmbRecipeSelector.DisplayMember = "Name";
            cmbRecipeSelector.ValueMember = "RecipeId";
            categoryComboBox.SelectedValueChanged += new EventHandler(categoryCmb_SelectedValueChanged);
            cookingTimer.Tick += new EventHandler(cookingTimer_Tick);
        }

        private void LoadIngredients()
        {
            // get unique ingredients
            ingredients = new List<Ingredient>();
            Dictionary<string, bool> addedIngredients = new Dictionary<string, bool>();

            foreach (Recipe r in recipes)
            {
                foreach (Ingredient i in r.Ingredients)
                {
                    if (i.Name != null && !addedIngredients.ContainsKey(i.Name.ToLower()))
                    {
                        ingredients.Add(i);
                        addedIngredients.Add(i.Name.ToLower(), true);
                    }
                }
            }
            ingredients.Sort();
        }

        void recipeBindingSource_CurrentChanged(object sender, EventArgs e)
        {
            //prepTimer();
        }

        void cookingTimer_Tick(object sender, EventArgs e)
        {
            if (this.e.Hours == 0 && this.e.Minutes == 0 && this.e.Seconds == 0)
            {
                cookingTimer.Stop();
                btnStartTimer.Text = "Start Timer";
            }
            else
            {
                this.e.Decrement();
                updateStatusStrip();
            }
        }

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveRecipes();
            this.Close();
        }

        public void SaveRecipes()
        {
            XmlWriterSettings settings = new XmlWriterSettings();
            settings.Indent = true;
            settings.Encoding = Encoding.UTF8;
            XmlWriter writer = XmlWriter.Create("Recipes.xml", settings);
            XmlSerializer x = new XmlSerializer(recipes.GetType());

            // put all recipes back in the list
            if (filteredOffRecipes.Count > 0)
            {
                foreach (Recipe r in filteredOffRecipes)
                    recipes.Add(r);
            }

            if (filteredOffRecipes2.Count > 0)
            {
                foreach (Recipe r in filteredOffRecipes2)
                    recipes.Add(r);
            }

            x.Serialize(writer, recipes);
            writer.Close();
        }

        public void LoadRecipes()
        {
            XmlReader reader = new XmlTextReader("Recipes.xml");
            XmlSerializer x = new XmlSerializer(recipes.GetType());
            recipes = x.Deserialize(reader) as List<Recipe>;
            reader.Close();
            setStepIdentity();
        }

        public void LoadCategorySelect()
        {
            Category.LoadCategories();
            categoryBindingSource1.DataSource = Category.Categories;
            categoryComboBox.DataSource = Category.Categories;
            categoryComboBox.DisplayMember = "Name";
            categoryComboBox.ValueMember = "Id";
        }

        private void loadRecipesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            LoadRecipes();
            recipeBindingSource.DataSource = recipes;
        }

        private void saveRecipesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveRecipes();
        }

        private void categoryCmb_SelectedValueChanged(object sender, EventArgs e)
        {
            (recipeBindingSource.Current as Recipe).CategoryId = (int)categoryComboBox.SelectedValue;
        }

        private void setStepIdentity()
        {
            int i = 0;
            foreach (Recipe r in recipes)
            {
                foreach (Step s in r.Steps)
                {
                    if (s.StepId > i)
                        i = s.StepId;
                }
                r.StepIdentity = i;
                i = 0;
            }
        }

        private void steps_RowEnter(object sender, DataGridViewCellEventArgs e)
        {
            if ((stepsBindingSource.Current as Step).StepId == 0)
                (stepsBindingSource.Current as Step).StepId = ++(recipeBindingSource.Current as Recipe).StepIdentity;
        }

        private void btnStartTimer_Click(object sender, EventArgs e)
        {
            if (!cookingTimer.Enabled)
            {
                prepTimer();
                cookingTimer.Start();
                btnStartTimer.Text = "Stop Timer";
            }
            else
            {
                cookingTimer.Stop();
                btnStartTimer.Text = "Start Timer";
            }
        }

        private void prepTimer()
        {
            cookingTimer.Stop();
            btnStartTimer.Text = "Start Timer";
            try
            {
                e = new ETimer((recipeBindingSource.Current as Recipe).BakingTime);
                tssProgressBar.Maximum = e.TotalSeconds;
                tssProgressBar.Value = 0;
            }
            catch (InvalidTimeFormat itf)
            {
                System.Diagnostics.Trace.WriteLine("The time formate could not be parsed for (" + typeof(ETimer) + "). Error: " + itf.Message);
                e = new ETimer();
                tssProgressBar.Maximum = e.TotalSeconds;
            }
        }

        private void setUpFiltersComboBoxes()
        {
            // set up the category filter
            populateCategoryFilter();
            // set up the ingredient filters
            populateIngredientFilters();
        }

        private void populateIngredientFilters()
        {
            // we need to add the ingredients along with a static select choice
            // adding the combo boxes to a list
            comboFilters.Add(cmbFilter1);
            comboFilters.Add(cmbFilter2);
            comboFilters.Add(cmbFilter3);
            comboFilters.Add(cmbFilter4);
            comboFilters.Add(cmbFilter5);

            foreach (ComboBox cmb in comboFilters)
            {
                foreach (Ingredient i in ingredients)
                {
                    if (i.Name != null)
                        cmb.Items.Add(i.Name);
                }
                cmb.SelectedIndex = 0;
            }
        }

        private void populateCategoryFilter()
        {
            // here we will add the categories to the combo filter
            Category cat = new Category()
            {
                Id = 0,
                Name = "Select Category..."
            };

            filterCategoryCmb.Items.Add(cat);

            filterCategoryCmb.DisplayMember = "Name";
            filterCategoryCmb.ValueMember = "Id";

            foreach (Category c in Category.Categories)
            {
                filterCategoryCmb.Items.Add(c);
            }

            filterCategoryCmb.SelectedIndex = 0;
            filterCategoryCmb.SelectedIndexChanged += new EventHandler(categoryFilter_SelectedIndexChanged);
        }

        private void updateStatusStrip()
        {
            tssProgressBar.PerformStep();
            tssLblTimeRemaining.Text = e.SHours + ":" + e.SMinutes + ":" + e.SSeconds;
        }

        private void categoryFilter_SelectedIndexChanged(object sender, EventArgs e)
        {
            // filter on category
            if (((filterCategoryCmb.SelectedItem as Category).Id) > 0)
            {
                AddFilteredRecipes();
                filteredOffRecipes.Clear();
                List<Recipe> tmpRecipe = new List<Recipe>();
                foreach (Recipe r1 in recipes)
                {
                    tmpRecipe.Add(r1);
                }

                foreach (Recipe r in tmpRecipe)
                {
                    if (!(r.CategoryId == Convert.ToInt32((filterCategoryCmb.SelectedItem as Category).Id)))
                    {
                        filteredOffRecipes.Add(r);
                        recipeBindingSource.Remove(r);
                    }
                }
                //ReLoadRecipeSelect();
                cmbRecipeSelector.Refresh();
            }
            else
            {
                AddFilteredRecipes();
                filteredOffRecipes.Clear();
            }
            recipes.Sort();
        }

        private void AddFilteredRecipes()
        {
            foreach (Recipe r in filteredOffRecipes)
            {
                recipeBindingSource.Add(r);
            }
        }
        
        private int m_currentPrintLine = 0;
        private string[] lines;

        private void ctPrintDocument_PrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            float yPos = 0f;
            int count = 0;
            float leftMargin = e.MarginBounds.Left;
            float topMargin = e.MarginBounds.Top;
            string line = null;
            Font f = new Font(new FontFamily("Arial"), 12, GraphicsUnit.Point);
            float linesPerPage = e.MarginBounds.Height /
                f.GetHeight(e.Graphics);
            //m_current Print Line is a class scope variable of type int.
            while (m_currentPrintLine < lines.Length && count < linesPerPage)
            {
                line = lines[m_currentPrintLine];  //Lines is a string array.
                m_currentPrintLine++;
                yPos = topMargin + count * f.GetHeight(e.Graphics);
                e.Graphics.DrawString(line, f, Brushes.Black, leftMargin, yPos, new StringFormat());
                count++;
            }

            if (m_currentPrintLine < lines.Length)
            {
                e.HasMorePages = true;
            }
        }

        private void printPreviewToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Recipe r = recipeBindingSource.Current as Recipe;
            char[] c = new char[] {
                '\r'
            };

            lines = r.ToString().Split(c);
            m_currentPrintLine = 0;
            printPreviewDialog1.ShowDialog();
        }

        private void printToolStripMenuItem1_Click(object sender, EventArgs e)
        {
            Recipe r = recipeBindingSource.Current as Recipe;
            char[] c = new char[] {
                '\r'
            };

            lines = r.ToString().Split(c);
            m_currentPrintLine = 0;
            printDocument1.Print();
        }

        private void cmbFilter_SelectedIndexChanged(object sender, EventArgs e)
        {
            AddFilteredIngredientRecipes();
            filteredOffRecipes2.Clear();
            List<string> filters = new List<string>();
            foreach (ComboBox cmb in comboFilters)
            {
                if (cmb.SelectedIndex > 0)
                {
                    filters.Add(cmb.SelectedItem.ToString());
                }
            }

            bool keepRecipe = false;
            List<Recipe> tmp = new List<Recipe>();
            foreach (Recipe r in recipes)
            {
                tmp.Add(r);
            }

            // apply filter
            if (filters.Count > 0)
            {
                foreach (Recipe r in tmp)
                {
                    keepRecipe = false;
                    foreach (Ingredient i in r.Ingredients)
                    {
                        foreach (string s in filters)
                        {
                            if (i.Name == null) continue;

                            if (i.Name.ToLower().Equals(s.ToLower())) keepRecipe = true;
                        }
                    }

                    if (!keepRecipe)
                    {
                        filteredOffRecipes2.Add(r);
                        recipeBindingSource.Remove(r);
                    }
                }
            }
        }

        private void AddFilteredIngredientRecipes()
        {
            foreach (Recipe r in filteredOffRecipes2)
            {
                recipeBindingSource.Add(r);
            }
        }
    }
}
